Referring to FIG. 1, a conventional data processing system comprises a CPU 12 which may be implemented by a microprocessor, a system memory 14 which usually is in the form of dynamic random access semiconductor memory, and a basic input/output system (BIOS) 16 which develops appropriate electrical signals for testing and controlling the various hardware devices within the system before control is assumed by the operating system during initialization. An input/output (I/O) controller 18 contains basic resources, such as interrupt controllers and DMA controllers which relieve the microprocessor from involvement in every task that is performed by the system. Other controllers, designated by block 20, develop signals necessary for operating peripherals such as hard disk and floppy drives, video monitor and keyboard.
Computers perform complicated tasks by segmenting any task into many smaller task and executing those tasks repetitively or sequentially, and at very high speed, under control of fixed programming called an operating system (example: DOS) which interacts with the computer components themselves, and application software (example: spreadsheet) which interacts with the user and is customized for each user application. The computer system, while executing these programs, responds both to signals developed internally and those developed from the outside to interrupt its normal execution and attend to special tasks.
In any real-time microprocessor based system, the ability to efficiently handle these interrupts in a timely manner has a considerable effect on the overall performance of the system. When activated, interrupts temporarily or permanently suspend the operation of the microprocessor and redirect operation to an interrupt routine. Such interrupt routines may represent software driven routines, such as a subroutine calling a special task, or may be driven by an external input (e.g., keyboard interrupt).
Interrupt servicing is conventionally carried out as shown in the flow chart of FIG. 2. Assume that a command to print a document is received from the keyboard (step 20). The application software generates an interrupt signal demanding immediate attention by the operating system (step 22). The value of the interrupt tells the operating system what service is being requested.
The interrupt signal is intercepted by the I/O controller that in turn notifies the CPU that an interrupt has occurred and requires immediate attention. The CPU saves the memory address of the current operation, reads from a data register, onto a "stack" in the memory 14 (step 24), and then reads the memory address associated with the interrupt to find an address vector to a location describing how to carry out the function defined by the interrupt (26). In this example, a BIOS routine takes over, sending the appropriate characters stored elsewhere in the memory to the printer. Assuming the BIOS controlled print routine is performed successfully, the BIOS sends an interrupt return instruction to the CPU, directing it to retrieve from the top of the memory stack the address of the application software routine that was being executed when the interrupt request was received, and restore operation.
Occasionally, a condition known as a "nested interrupt" arises, when more than one interrupt service are to be carried in sequence. This can result from interrupt service routines that require the service of other interrupt routines to carry out the function specified, or from multiple interrupts arriving independently.
Inefficiency in handling interrupts arises from the fact that a significant amount of time is expended by the interrupt service routine in order to handle each incoming interrupt by saving and restoring the state of the machine. For example, it may take 60 to 70 CPU clock cycles to save the contents of all data registers, and an additional 60 to 70 clock cycles to restore the contents of the data registers and continue processing.
To better cope with this situation, so-called "shadow" registers have been employed to save the contents of corresponding data registers upon an interrupt call. In shadow register architecture, each data register is provided with a corresponding "shadow" register. When an interrupt is generated the contents of all data registers, such as register DR, are each simultaneously stored into the corresponding shadow register SHR, as shown in FIG. 3. This simultaneous transfer of data may be accomplished in as little as one clock cycle. The interrupt routine is then executed. When the interrupt routine is completed, processing is returned to the point where the interrupt routine is generated by transferring the contents of the shadow registers back to their corresponding data registers. This simultaneous transfer of data can take place in as little as one additional clock cycle.
The use of shadow registers eliminates the time problem associated with the ISR approach. However, if only one shadow register is provided for each data register within the microprocessor, interrupt routines cannot be nested. In other words, if an interrupt routine is generated during the execution of an existing interrupt routine, the original status of the data registers will be lost. The first interrupt routine will force the contents of the data registers to be stored into the corresponding shadow registers. The interrupt routine is then executed. If a second interrupt routine is executed during the first interrupt routine, the contents of the data registers, as determined by the first interrupt routine, will be transferred to the shadow registers. The data in the shadow registers will then be lost. Thus, when the first and second interrupt routines are completed, processing cannot be returned to the original point where the first interrupt routine was generated as the original status of the data registers has not been preserved.
In order to overcome this difficulty, several shadow registers have been used, as shown in FIG. 4. By providing 2, 3, or more shadow registers, e.g., SH1, SH1a, SH1b, etc., for each data register, e.g. D1, a number of nested interrupt routines may be executed without the loss of register data. As each set of nested interrupt routines is generated, the contents of each data register is transferred to a corresponding shadow register. As there are a number of corresponding shadow registers for each data register, the contents of each data register for each interrupt routine may be saved. These groups of data registers are configured as a stack (e.g., in a LIFO format) such that the contents of the data register at the generation of the previous interrupt routine is always at the top of the stack.
While such an approach provides fast storage of the contents of the data registers and allows the nesting of interrupt routines, a large amount of hardware is necessary to implement such a design. In particular, a number of shadow registers equals to the permissible number of nested interrupts must be provided for each data register, increasing the complexity and cost of the microprocessor. However, it is still possible to overflow the stack if more than the prescribed number of nested interrupts are generated. Hence, shadow registering of nested interrupts is not cost effective as well as imposes a randomness to the design of the CPU per application
The conventional approach accordingly has been to ignore use of shadow registers, implementing instead the ISR technique, to service nested interrupts. However, this method wastes processor resources that are already imbedded in the hardware.